import random
import numpy as np

from Cell import Cell
from Config import Config


class Map:
    __cells = None
    __debug = False

    def __init__(self, debug=False):
        self.__debug = debug
        self.__cells = np.array(
            [np.array([Cell(Config.CELL_SIZE, x, y, Config.GRAY1)
                       for x in range(Config.CLIENT_WIDTH)]) for y in range(Config.CLIENT_HEIGHT)])

    def build(self):
        self.__buildMines()
        return self

    def cell(self, x, y):
        return self.__cells[x, y]

    def clickAll(self):
        for x in range(Config.CLIENT_WIDTH):
            for y in range(Config.CLIENT_HEIGHT):
                self.__cells[y, x].click()

    def __buildMines(self):
        mineNum = int(Config.CLIENT_WIDTH * Config.CLIENT_HEIGHT * Config.MINE_PERCENT / 100)
        for i in range(mineNum):
            while True:
                x = random.randint(0, Config.CLIENT_WIDTH - 1)
                y = random.randint(0, Config.CLIENT_HEIGHT - 1)
                if not self.__cells[y, x].mined():
                    self.__cells[y, x].mine()
                    break

        for x in range(Config.CLIENT_WIDTH):
            for y in range(Config.CLIENT_HEIGHT):
                if self.__cells[y, x].mined():
                    self.__addNeighbourMineNum(x, y)

        if self.__debug:
            print('Total mines:', mineNum)
            for x in range(Config.CLIENT_HEIGHT):
                print([str(cell) for cell in self.__cells[x]])

    def __addNeighbourMineNum(self, x, y):
        for i in (x - 1, x, x + 1):
            if not (0 <= i < Config.CLIENT_WIDTH):
                continue
            for j in (y - 1, y, y + 1):
                if 0 <= j < Config.CLIENT_HEIGHT:
                    self.__cells[j, i].incMineNum()

    def checkDone(self):
        for i in range(Config.CLIENT_WIDTH):
            for j in range(Config.CLIENT_HEIGHT):
                cell = self.__cells[j, i]
                if (cell.mined() and not cell.marked()) or (not cell.mined() and cell.marked()):
                    return False
        return True

    def clickEmptyNeighbour(self, x, y, history=None):
        if not history:
            history = set()
        cell = self.__cells[y, x]
        if not cell.isEmpty():
            return
        history.add((x, y))
        for i in (x - 1, x, x + 1):
            if 0 > i or i >= Config.CLIENT_WIDTH:
                continue
            for j in (y - 1, y, y + 1):
                if 0 > j or j >= Config.CLIENT_HEIGHT:
                    continue
                if (i, j) not in history:
                    self.__cells[j, i].click()
                    self.clickEmptyNeighbour(i, j, history)
